<template>
  <!-- 此表格为横向表格 -->
  <div class="crossWise">
    <div class="title">不成熟的想法测试标题</div>
    <div class="content">
      <!-- 循环所有的类型生成对应的配置项页面 -->
      <div class="line" v-for="item in cols" :key="'item' + item.prop" :style="{ width: item.width || 50 + '%' }">
        <!-- 展示自定义插槽 -->
        <div class="line_child" v-if="item.type == 'custom'">
          <label class="label" :style="{ width: item.labelWidth || 20 + '%' }">{{item.label}}</label>
          <div class="line_box flex-1">
            <slot :name="item.prop" :data="{...model}"></slot>
          </div>
        </div>
        <!-- 展示文字 -->
        <div class="line_child" v-if="item.type == 'text'">
          <label class="label" :style="{ width: item.labelWidth || 20 + '%' }">{{item.label}}</label>
          <div class="line_text line_box flex-1" :title="model[item.prop]">{{model[item.prop]}}</div>
        </div>
        <!-- 展示输入框 -->
        <div class="line_child" v-if="item.type == 'input'">
          <label class="label" :style="{ width: item.labelWidth || 20 + '%' }">{{item.label}}</label>
          <div class="flex-1 line_box line_input">
            <el-input @blur="validateFn(item.prop)" v-model="model[item.prop]" placeholder="请输入"></el-input>
            <div v-if="validateModel.errTips[item.prop]" class="errTip animate__animated animate__fadeInDown fadeInDown">{{validateModel.errTips[item.prop]}}</div>
          </div>
        </div>
        <!-- 展示下拉选择 -->
        <div class="line_child" v-if="item.type == 'select'">
          <label class="label" :style="{ width: item.labelWidth || 20 + '%' }">{{item.label}}</label>
          <div class="flex-1 line_box line_input">
            <el-select v-model="model[item.prop]" placeholder="请选择" clearable 
              :multiple="item.multiple"
              collapse-tags
              :filterable="item.filterable ? true : false"
            >
              <el-option
                v-for="(items, i) in item.select"
                :key="'select_' + i"
                :label="items.label || items.text"
                :value="items.value"
              ></el-option>
            </el-select>
          </div>
        </div>
        <!-- 展示时间选择器 -->
        <div class="line_child" v-if="item.type == 'date'">
          <label class="label" :style="{ width: item.labelWidth || 20 + '%' }">{{item.label}}</label>
          <div class="flex-1 line_box line_input">
            <el-input v-model="model[item.prop]" placeholder="请输入"></el-input>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
// 配置项type的状态类型
export type crossType = 'input' | 'select' | 'text' | 'date' | 'custom'

// 下拉选择的类型
export interface selectType{
  label: String,
  text:  String,
  value: Number | String | Boolean,
}

export interface validateTip{
  prop: String,
  rules: any[]
}

export interface fnTips{
  (x:string | number, y?: any): string | undefined
}

export interface validateModel{
  tipValidate: validateTip[],
  errTips: { [propsName:string]: String }
}

export interface crosswiseType{
  label: string, // 左侧文字：
  prop: string,  // 绑定字段：
  type: crossType, // 状态类型
  width: number, // 当前配置格子占比
  labelWidth?: number, // 左侧文字占比
  disabled?: boolean, // 是否禁用
  max?: number, // 当前输入文字最大长度
  min?: number, // 当前输入最小文字
  required?: boolean, // 当前项是否为必填
  validate?: fnTips, // 校验规则
  // 衍生选择类的类型
  select?: selectType[], // 选择下拉的类型
  multiple?: boolean, // 是否开启多选
  filterable?: boolean, // 是否开启模糊匹配
}
import type { PropType } from "vue";
import { defineProps, reactive, useContext, onMounted } from "vue";
const { expose } = useContext()
const { cols, model, title }  = defineProps({
  // 横表的配置项
  cols:{
    type: Array as PropType<crosswiseType[]>,
    require: true
  },
  // 横标对应的展示数据集合
  model:{
    require: true,
    type: Object as any
  },
  // 横表的标题(页眉)
  title:{
    type: String,
    default: "",
  },
})

let validateModel  = reactive<validateModel>({
  tipValidate: [],
  errTips:{}
})

// 生成对应的校验规则
const rulesCreated = () =>{
  cols?.forEach(v=>{
    let ruleArr = [];
    // 生成必填规则
    if(v.required){
      ruleArr.push({
        fn: (val: string|number)=>{ return model[val] != "" && model[val] != undefined ? false : true },
        msg: `${v.label}为必填项`
      })
    }
    // 最大长度限制
    if(v.max){
      ruleArr.push({
        fn: (val: string|number)=>{ if(v.max){ return String(model[val]).length > v.max ? false : true } },
        msg: `${v.label}最大长度为${v.max}`
      })
    }
    // 自定义校验规则校验
    if(v.validate){
      ruleArr.push({
        fn: (val: string|number)=>{ return v.validate && v.validate(model[val],{...model})}
      })
    }
    validateModel.tipValidate.push({
      prop: v.prop,
      rules: ruleArr
    })
  })
}

// 触发校验规则
const validateFn = (prop:string)=>{
  let model = validateModel.tipValidate.find((v:validateTip)=> v.prop == prop);
  if(model){
    for(let i = 0; i<model.rules.length; i++){
      let val = model.rules[i];
      // 对内置校验进行校验
      if(val.fn){
        let type = val.fn(prop)
        console.log(val.msg)
        if(type){
          validateModel.errTips[prop] = val.msg || type;
          break
        }else{
          validateModel.errTips[prop] = "";
        }
      }
    }
  }
}

// 触发提交校验
const verify = () =>{
  return new Promise((resolve,rejects)=>{
    validateModel.errTips = {};
    cols?.forEach((v:crosswiseType)=>{
      validateFn(v.prop)
    })
    let errArr = Object.keys(validateModel.errTips);
    let type = false;
    for(let i = 0;i< errArr.length; i++){
      if(validateModel.errTips[errArr[i]]){
        type = true;
        break
      }
    }
    type? resolve(model) : rejects()
  })
}

expose({
  verify
})

onMounted(()=>{
  rulesCreated()
})

</script>

<style lang="scss" scoped>
@import '@/assets/systemCss/component/crossWise.scss'
</style>